package com.munisense.webservices.javaclient;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

/**
 * Container class for Result Query options
 * 
 * @author Joost Pastoor
 */
public class ResultQueryOptions {

	/**
	 * Unix timestamp in milliseconds indicating the start of the query.
	 */
	private Integer starttime = null;

	/**
	 * Unix timestamp in milliseconds indicating the end of the query.
	 */
	private Integer endtime;

	/**
	 * Value in milliseconds indicating for what timeperiod the results should
	 * be grouped to calculate average/min/max.
	 */
	private Integer samplerate;

	/**
	 * Number of samples to skip before returning other samples.
	 */
	private Integer offset;

	/**
	 * Max amount of rows to return.
	 */
	private Integer rowcount;

	/**
	 * Field to sort the results on TODO Make this an enum
	 */
	private String order_field = null;

	/**
	 * Direction to sort the results in on order_field. Can be either "asc"
	 * (Ascending) or "desc" (Descending) 
	 */
	private OrderDir order_dir = null;

	public enum OrderDir {
		ASCENDING("asc"), DESCENDING("desc");

		private String code;

		private OrderDir(String c) {
			code = c;
		}

		public String toString() {
			return code;
		}
	}
	
	/**
	 * Scale of the values, uses scale operator
	 */
	private Integer scale = null;

	/**
	 * Can be either "lin" (Linear) or "log" (Logarithmic)
	 */
	private ScaleType scale_type = null;

	public enum ScaleType {
		LOGARITHMIC("log"), LINEAR("lin");

		private String code;

		private ScaleType(String c) {
			code = c;
		}

		public String toString() {
			return code;
		}
	}

	/**
	 * Arithmic expression to use in conjuction with scale on the values.
	 * Default is *.
	 */
	private ScaleOperator scale_operator = null;

	public enum ScaleOperator {
		MULTIPLY("*"), DIVIDE("/");

		private String code;

		private ScaleOperator(String c) {
			code = c;
		}

		public String toString() {
			return code;
		}
	}
	
	/**
	 * @param starttime
	 * @param endtime
	 * @param samplerate
	 * @param offset
	 * @param rowcount
	 * @param order_field
	 * @param order_dir
	 * @param scale
	 * @param scale_type
	 * @param scale_operator
	 */
	public ResultQueryOptions(Integer starttime, Integer endtime, Integer samplerate, Integer offset, Integer rowcount, String order_field, OrderDir order_dir, Integer scale, ScaleType scale_type, ScaleOperator scale_operator) {
		this.starttime = starttime;
		this.endtime = endtime;
		this.samplerate = samplerate;
		this.offset = offset;
		this.rowcount = rowcount;
		this.order_field = order_field;
		this.order_dir = order_dir;
		this.scale = scale;
		this.scale_type = scale_type;
		this.scale_operator = scale_operator;
	}

	public ResultQueryOptions() {

	}

	/**
	 * @return the starttime.  Starttime is in milliseconds.
	 */
	public Integer getStarttime() {
		return starttime;
	}

	/**
	 * @param starttime
	 *            the starttime to set. Starttime is in milliseconds.
	 */
	public void setStarttime(Integer starttime) {
		this.starttime = starttime;
	}

	/**
	 * @return the endtime. Endtime is in milliseconds.
	 */
	public Integer getEndtime() {
		return endtime;
	}

	/**
	 * @param endtime
	 *            the endtime to set. Endtime is in milliseconds.
	 */
	public void setEndtime(Integer endtime) {
		this.endtime = endtime;
	}

	/**
	 * @return the samplerate. Samplerate is in milliseconds.
	 */
	public Integer getSamplerate() {
		return samplerate;
	}

	/**
	 * @param samplerate
	 *            the samplerate to set. Samplerate is in milliseconds.
	 */
	public void setSamplerate(Integer samplerate) {
		this.samplerate = samplerate;
	}

	/**
	 * @return the offset
	 */
	public Integer getOffset() {
		return offset;
	}

	/**
	 * @param offset
	 *            the offset to set
	 */
	public void setOffset(Integer offset) {
		this.offset = offset;
	}

	/**
	 * @return the rowcount
	 */
	public Integer getRowcount() {
		return rowcount;
	}

	/**
	 * @param rowcount
	 *            the rowcount to set
	 */
	public void setRowcount(Integer rowcount) {
		this.rowcount = rowcount;
	}

	/**
	 * @return the order_field
	 */
	public String getOrderField() {
		return order_field;
	}

	/**
	 * @param order_field
	 *            the order_field to set
	 */
	public void setOrderField(String order_field) {
		this.order_field = order_field;
	}

	/**
	 * @return the order dir
	 */
	public OrderDir getOrderDir() {
		return order_dir;
	}

	/**
	 * @param order_dir
	 *            the order_dir to set
	 */
	public void setOrderDir(OrderDir order_dir) {
		this.order_dir = order_dir;
	}

	/**
	 * @return the scale
	 */
	public Integer getScale() {
		return scale;
	}

	/**
	 * @param scale
	 *            the scale to set
	 */
	public void setScale(Integer scale) {
		this.scale = scale;
	}

	/**
	 * @return the scale_type
	 */
	public ScaleType getScaleType() {
		return scale_type;
	}

	/**
	 * @param scale_type
	 *            the scale_type to set
	 */
	public void setScaleType(ScaleType scale_type) {
		this.scale_type = scale_type;
	}

	/**
	 * @return the scale_operator
	 */
	public ScaleOperator getScaleOperator() {
		return scale_operator;
	}

	/**
	 * @param scale_operator
	 *            the scale_operator to set
	 */
	public void setScaleOperator(ScaleOperator scale_operator) {
		this.scale_operator = scale_operator;
	}

	/**
	 * This method returns a query string to be used when requesting result
	 * queries containing the different query parameters as contained in this
	 * object.
	 * 
	 * @return String to be used in URL
	 */
	public String generateQueryString() {
		// Container for the result parts
		List<String> returnParts = new ArrayList<String>();

		// Loop over the different fields this class has
		for (Field field : ResultQueryOptions.class.getDeclaredFields()) {
			try {
				if (field.get(this) != null) {
					returnParts.add(field.getName() + "=" + field.get(this));
				}
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}

		// Return the concatenated query string result
		return StringUtils.join(returnParts, "&");
	}
}
